1 package joeq.Util;
2
3 /***
4 * Based on code from AspectWerks and slightly modified.
5 *
6 * The original can be found here:
7 *
8 * @url http://cvs.codehaus.org/viewrep/~raw,r=1.3/aspectwerkz/aspectwerkz4/src/main/org/codehaus/aspectwerkz/definition/DescriptorUtil.java
9 * */
10
11 import java.util.HashMap;
12 import java.util.Map;
13 import java.util.StringTokenizer;
14
15 /***
16 * The signature of a method that is available from the BCEL library uses descriptors as defined in Section 4.3 of the
17 * Java Virtual Machine specificaiton. Javadoc and Java do not use signatures in this same format. This class converts
18 * the Javadoc/Java signature format to that used by the JVM spec. To summarize the descriptors <code> A method
19 * descriptor represents the parameters that the method takes and the value that it returns:
20 * <p/>
21 * MethodDescriptor: ( ParameterDescriptor* ) ReturnDescriptor
22 * <p/>
23 * A parameter descriptor represents a parameter passed to a method:
24 * <p/>
25 * ParameterDescriptor: FieldType
26 * <p/>
27 * A return descriptor represents the type of the value returned from a method. It is a series of characters generated
28 * by the grammar:
29 * <p/>
30 * ReturnDescriptor: FieldType V
31 * <p/>
32 * The character V indicates that the method returns no value (its return type is void). </code>
33 * <p/>
34 * <code> A field descriptor represents the type of a class, instance, or local variable. It is a series of characters
35 * generated by the grammar:
36 * <p/>
37 * FieldDescriptor: FieldType
38 * <p/>
39 * ComponentType: FieldType
40 * <p/>
41 * FieldType: BaseType ObjectType ArrayType
42 * <p/>
43 * BaseType: B C D F I J S Z
44 * <p/>
45 * ObjectType: L <classname> ;
46 * <p/>
47 * ArrayType: [ ComponentType
48 * <p/>
49 * The characters of BaseType, the L and ; of ObjectType, and the [ of ArrayType are all ASCII characters. The
50 * <classname> represents a fully qualified class or interface name. For historical reasons it is encoded in internal
51 * form (4.2). The interpretation of the field types is as shown in Table 4.2.
52 * <p/>
53 * BaseType Character Type Interpretation ---------------------------------------------- B byte
54 * signed byte C char Unicode character D double double-precision
55 * floating-point value F float single-precision floating-point value I int
56 * integer J long long integer L<classname>; reference an instance of class <classname> S
57 * short signed short Z boolean true or false [ reference one array dimension
58 *
59 * @author <a href="mailto:mpollack@speakeasy.org">Mark Pollack</a>
60 */
61 public class DescriptorUtil {
62 private static Map _paramTypeMap = new HashMap();
63
64 private static Map _returnTypeMap = new HashMap();
65
66 static {
67 _paramTypeMap.put("byte", "B");
68 _paramTypeMap.put("char", "C");
69 _paramTypeMap.put("double", "D");
70 _paramTypeMap.put("float", "F");
71 _paramTypeMap.put("int", "I");
72 _paramTypeMap.put("long", "J");
73
74
75
76
77 _paramTypeMap.put("java.lang.Object", "Ljava/lang/Object;");
78 _paramTypeMap.put("short", "S");
79 _paramTypeMap.put("boolean", "Z");
80
81
82 _paramTypeMap.put("array reference", "[");
83 _returnTypeMap.put("void", "V");
84 }
85
86 /***
87 * Converts from the Java/Javadoc method signature the JVM spec format.
88 *
89 * @param javadocSig method signature as returned via Javadoc API.
90 * @param javadocReturnType return type as returned via Javadoc API.
91 * @return mtehod signature as defined in the JVM spec.
92 */
93 public static String convert(String javadocSig, String javadocReturnType) {
94
95 String javadocSigTrim = javadocSig.substring(1, javadocSig.length() - 1);
96 StringTokenizer st = new StringTokenizer(javadocSigTrim, ",");
97 StringBuffer jvmBuff = new StringBuffer("(");
98 while (st.hasMoreTokens()) {
99
100 String sigElement = st.nextToken().trim();
101 if (_paramTypeMap.containsKey(sigElement)) {
102 jvmBuff.append(_paramTypeMap.get(sigElement));
103 }
104 }
105 jvmBuff.append(")");
106 if (_returnTypeMap.containsKey(javadocReturnType)) {
107 jvmBuff.append(_returnTypeMap.get(javadocReturnType));
108 }
109 return jvmBuff.toString();
110 }
111
112 /***
113 * Convert a JVM signature as defined in the JVM spec to that used in the Java.
114 *
115 * @param jvmSignature The JVM format signature.
116 * @return a <code>String[]</code> containing the method parameter as elements of the array.
117 */
118 public static String[] getParameters(final String jvmSignature) {
119 int i = 0;
120 if (jvmSignature.charAt(i) != '(') {
121 return null;
122 }
123 int j = 0;
124 StringBuffer stringbuffer = new StringBuffer();
125 for (i++; i < jvmSignature.length();) {
126 if (jvmSignature.charAt(i) == ')') {
127 i++;
128 break;
129 }
130 if (i > 1) {
131
132 stringbuffer.append(" ");
133 }
134 i = jvmFormatToJavaFormat(jvmSignature, i, stringbuffer);
135
136
137 j++;
138 }
139
140
141 String convertedString = stringbuffer.toString();
142 String[] as = new String[j];
143 int k = 0;
144 StringTokenizer st = new StringTokenizer(convertedString);
145 while (st.hasMoreTokens()) {
146 as[k++] = st.nextToken();
147 }
148 return as;
149 }
150
151 /***
152 * The utility method that does the real work of parsing through the JVM formatted string and adding an converted
153 * method parameter description to the StringBuffer.
154 *
155 * @param jvmFormat The JVM formatted string that is being parsed.
156 * @param i The offset into the string being parsed.
157 * @param stringbuffer The storage for building the converted method signature.
158 * @return new offset location for parsing.
159 * @TODO this an extremely ugly method (the int an stringbuffer params must be removed)
160 */
161 public static int jvmFormatToJavaFormat(final String jvmFormat, int i, StringBuffer stringbuffer) {;
162 String s1 = "";
163
164
165 for (; jvmFormat.charAt(i) == '['; i++) {
166 s1 = s1 + "[]";
167 }
168 startover: switch (jvmFormat.charAt(i)) {
169 case 66:
170 stringbuffer.append("byte");
171 break;
172 case 67:
173 stringbuffer.append("char");
174 break;
175 case 68:
176 stringbuffer.append("double");
177 break;
178 case 70:
179 stringbuffer.append("float");
180 break;
181 case 73:
182 stringbuffer.append("int");
183 break;
184 case 74:
185 stringbuffer.append("long");
186 break;
187 case 83:
188 stringbuffer.append("short");
189 break;
190 case 90:
191 stringbuffer.append("boolean");
192 break;
193 case 86:
194 stringbuffer.append("void");
195 break;
196 case 76:
197
198
199 for (i++; i < jvmFormat.length(); i++) {
200 if (jvmFormat.charAt(i) == '/') {
201
202 stringbuffer.append('.');
203 } else {
204 if (jvmFormat.charAt(i) == ';') {
205
206 break startover;
207 }
208
209
210 stringbuffer.append(jvmFormat.charAt(i));
211 }
212 }
213 break;
214 default:
215 return jvmFormat.length();
216 }
217 stringbuffer = stringbuffer.append(s1);
218 return ++i;
219 }
220 }